package main

import (
	"context"
	"fmt"
	"github.com/chromedp/cdproto/network"
	"log"
	entity2 "mp3/entity"
	"mp3/util"
	"os"
	"strings"
	"time"
)

const (
	DownLoadMethodCount = 2
)

func main() {
	filePath, _ := os.Getwd()
	log.Println("[" + filePath + "]")

	var entities []entity2.DownloadEntity
	entities = util.ReadConfigs(filePath, entities)

	if nil != entities {
		for index, source := range entities {
			log.Println("=====================================================================")
			log.Println(source.URL, "===", index, "===", source.FileName)
			if util.IsEmpty(source.PageOfParentTag) {
				source.StartPageIndex = 0
			}

			choosePages(source, true, source.StartPageIndex)
			log.Println("=========================over============================================")
		}
	}
}

func choosePages(configEntity entity2.DownloadEntity, firstPage bool, pageIndex int) {
	url := configEntity.URL
	errorIndex := 0
	var responseEntity entity2.ResponseEntity
	var flag bool
	var bk bool
	pageNum := 0

	for i := 0; i < util.PAGECOUNT; i++ {
		responseEntity, flag, bk, errorIndex, pageNum = choose(configEntity, pageIndex, url, errorIndex, firstPage, pageNum)

		if bk {
			break
		}
		firstPage = false
		if 0 == errorIndex {
			configEntity.StartPageIndex = pageNum + 1
			util.WriteConfigOfStartIndex(configEntity, 0)
		}

		if util.IsEmpty(configEntity.NextTag) && flag {
			break
		}
		url = util.NextPage(responseEntity.Document, configEntity, pageNum+1)

		if util.IsEmpty(url) {
			log.Println("playList------url break--", pageNum, "-----", url)
			break
		}
		log.Println("playList--------", i, "-----", url)
		pageNum++

	}
}

func choose(configEntity entity2.DownloadEntity, page int, url string, errorIndex int, firstPage bool, pageIndex int) (entity2.ResponseEntity, bool, bool, int, int) {

	allocCtx, cancel := util.CreateAllocCtx()
	defer cancel()

	responseEntity, playList, pageIndex := util.ChoosePlayList(configEntity, url, pageIndex, firstPage, allocCtx)

	length := len(playList)
	log.Println("playList-->over--", page, "--->", url)
	if length == 0 {
		log.Println("playList------playList break--", page-1, "-----", url)
		return responseEntity, true, false, errorIndex, pageIndex
	}
	playList = chooseStartIndex(playList, configEntity)

	forIndex := 0
	numIndex := 0
	num := int(util.RandomNum(20, 1))

	methodIndex := 0
	urlIndex := 0
	var flag bool
	var path string
	for i := 0; i < util.PAGECOUNT; i++ {
		if length <= forIndex {
			break
		}

		nextEntity := playList[forIndex]
		numIndex++
		titile := nextEntity.TitleNames[0]
		var audioURLS []string
		var heads map[string]map[string]string
		var cookies []*network.Cookie
		var resultFlag bool
		var resultFlag1 bool
		var resultNum int
		var urlHeadMap map[string]string

		if util.SwitchFileExsts1(titile, configEntity) {
			audioURLS, heads, urlHeadMap, cookies = util.SwitchChromedpTag1(configEntity, nextEntity.Url, allocCtx)
			if length-i < -1 {
				break
			}

			urlLength := len(audioURLS)
			for i := 0; i < urlLength; i++ {
				var header = util.MergeHead(urlHeadMap, heads[audioURLS[i]])

				responseEntity, resultFlag, resultFlag1, errorIndex, pageIndex, resultNum = chooseDownURL(configEntity, responseEntity, errorIndex, pageIndex, audioURLS[i], forIndex, length, i, nextEntity,
					urlIndex, flag, path, methodIndex, titile, header, cookies, num, numIndex, playList, url, firstPage, nil)
				if resultNum == -1 {
					if util.IsEmpty(configEntity.PageOfParentTag) {
						if errorIndex > 21 {
							return responseEntity, false, true, errorIndex, pageIndex
						}
					} else {
						if errorIndex > 11 {
							return responseEntity, false, true, errorIndex, pageIndex
						}
					}
				} else if resultNum == 1 {
					return responseEntity, resultFlag, resultFlag1, errorIndex, pageIndex
				}
			}

		}
		forIndex++
	}
	return responseEntity, false, false, errorIndex, pageIndex
}

func chooseDownURL(configEntity entity2.DownloadEntity, responseEntity entity2.ResponseEntity, errorIndex int, pageIndex int, audioURL string,
	forIndex int, length int, i int, nextEntity entity2.PlayListEntity, urlIndex int, flag bool, path string, methodIndex int, titile string, heads map[string]string,
	cookies []*network.Cookie, num int, numIndex int, playList []entity2.PlayListEntity, url string, firstPage bool, allocCtx context.Context) (entity2.ResponseEntity, bool, bool, int, int, int) {
	if util.IsEmpty(configEntity.PageOfParentTag) {
		if errorIndex > 21 {
			return responseEntity, false, true, errorIndex, pageIndex, 0
		}
	} else {
		if errorIndex > 11 {
			return responseEntity, false, true, errorIndex, pageIndex, 0
		}
	}

	if util.IsEmpty(audioURL) {
		//time.Sleep(util.Sleep_Value)
		forIndex++
		errorIndex++
		log.Println(configEntity.URL, "---continue---", length-i, nextEntity.Url)

		return responseEntity, false, true, errorIndex, pageIndex, -1
	}

	start := time.Now()
	log.Println(" \n  ")
	urlIndex = 0
	flag, path, methodIndex, urlIndex = download(responseEntity, configEntity, titile, audioURL, heads, cookies, methodIndex, urlIndex, allocCtx)
	if flag {
		flag = util.ClearAttr(path, configEntity, titile, audioURL)
		if flag {
			errorIndex = 0
			util.Sleep(configEntity, start)
			log.Println("play++++", length-i, "++++", configEntity.FileName, "+++num:", num, "+++numIndex:", numIndex, "++++over")
		} else {
			errorIndex++
			return responseEntity, false, true, errorIndex, pageIndex, -2
		}

		log.Println(" \n  ")
	} else {
		util.SleepTime(util.Default_Sleep_Value)
		errorIndex++
	}

	if numIndex >= num {
		responseEntity, playList, pageIndex = util.ChoosePlayList(configEntity, url, pageIndex, firstPage, allocCtx)
		numIndex = 0
		errorIndex = 0
		num = int(util.RandomNum(10, 1))
		length = len(playList)
	}
	return responseEntity, false, true, errorIndex, pageIndex, 1
}

func chooseStartIndex(playList []entity2.PlayListEntity, configEntity entity2.DownloadEntity) []entity2.PlayListEntity {
	if util.IsEmpty(configEntity.PageOfParentTag) && configEntity.StartIndex == 0 {
		return playList
	}
	var pls []entity2.PlayListEntity

	length := len(playList)
	for i := 0; i < length; i++ {
		if i >= configEntity.StartIndex {
			pls = append(pls, playList[i])
		}
	}
	return pls
}

func download(responseEntity entity2.ResponseEntity, configEntity entity2.DownloadEntity, titile string, audioURL string,
	heads map[string]string, cookies []*network.Cookie, downloadIndex int, urlIndex int, ctx context.Context) (bool, string, int, int) {
	var flag bool
	var path string
	oldDownloadIndex := downloadIndex

	if urlIndex == 0 {
		flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, downloadIndex, heads, cookies, responseEntity, ctx)
		if flag {
			return flag, path, downloadIndex, urlIndex
		}
		if oldDownloadIndex != 0 {
			flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, 0, heads, cookies, responseEntity, ctx)
			if flag {
				return flag, path, downloadIndex, urlIndex
			}
		}
		urlIndex++
	}
	index1 := strings.Index(audioURL, "?")
	if urlIndex == 1 {

		if index1 > 0 {
			audioURL = audioURL + "&"
		} else {
			audioURL = audioURL + "?"
		}
		t := fmt.Sprintf("t=%d", time.Now().Unix())
		audioURL = audioURL + t
		flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, downloadIndex, heads, cookies, responseEntity, ctx)

		if flag {
			return flag, path, downloadIndex, urlIndex
		}
		if oldDownloadIndex != 0 {
			audioURL = fmt.Sprintf(audioURL+"t=%d", time.Now().Unix())
			flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, 0, heads, cookies, responseEntity, ctx)

			if flag {
				return flag, path, downloadIndex, urlIndex
			}
		}
		urlIndex++
	}
	if urlIndex == 2 {
		if index1 > 0 {
			audioURL = audioURL[0:index1]
			flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, downloadIndex, heads, cookies, responseEntity, ctx)
			if flag {
				return flag, path, downloadIndex, urlIndex
			}
		}

		if oldDownloadIndex != 0 {
			audioURL = fmt.Sprintf(audioURL+"t=%d", time.Now().Unix())
			flag, path, downloadIndex = HttpDownloadResponse(audioURL, configEntity, titile, downloadIndex, heads, cookies, responseEntity, ctx)

			if flag {
				return flag, path, downloadIndex, urlIndex
			}
		}
	}
	urlIndex = 0
	return flag, "", downloadIndex, urlIndex
}

func HttpDownloadResponse(audioURL string, configEntity entity2.DownloadEntity, titile string, index int,
	heads map[string]string, cookies []*network.Cookie, responseEntity entity2.ResponseEntity, ctx context.Context) (bool, string, int) {
	var flag bool
	var path string

	if util.IsEmpty(audioURL) || strings.Index(audioURL, "http") == -1 {
		log.Println(audioURL)
		return flag, path, index
	}

	if index == 0 {
		flag, path = util.FfmpegDownload(responseEntity, configEntity, titile, audioURL)
		if flag {
			return flag, path, index
		}
		index++
	}
	index++
	if index == 1 {
		flag, path = util.DownloadCollyUtil(audioURL, ctx, configEntity, titile)
		if flag {
			return flag, path, index
		}
		index++
	}

	if index == 2 {
		flag, path = util.Download(audioURL, configEntity, titile, heads, cookies)
		if flag {
			return flag, path, index
		}
		index++
	}

	if index == 3 {
		flag, path = util.Download(audioURL, configEntity, titile, nil, cookies)
		if flag {
			return flag, path, index
		}
		index++
	}

	if index == 4 {
		flag, path = util.Download(audioURL, configEntity, titile, heads, nil)
		if flag {
			return flag, path, index
		}
		index++
	}

	flag, path = util.Download(audioURL, configEntity, titile, nil, nil)
	if flag {
		return flag, path, index
	}
	index = 0
	return flag, path, index

}
